﻿#region Header

/*
Behavioral Rating of Dancing Human Crowds based on Motion Patterns
By

Pascal Hauser 
Dipl. Ing. in Informatik, Hochschule für Technik Rapperswil, 2006
Master Thesis, Hochschule für Technik Rapperswil, 2008-2010

and

Raphael Gfeller
Dipl. Ing. in Informatik, Hochschule für Technik Rapperswil, 2006
Master Thesis, Hochschule für Technik Rapperswil, 2008-2010

*/

#endregion

#region Usings

using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Sebarf.Diagnostics.Interfaces;
using Tests.Basics.Optimization;

#endregion

namespace Tests.Basics {
	/// <summary>
	/// Description of the class
	/// </summary>
	[TestClass]
	public class TestOptimization {
		#region Test Methods

		// public methods located here

		[TestMethod]
		public void TestCaseOne() {
			var model = new DestrictiveModel();
			// define possible args
			model.AddArgs("X", new Parameter { MaxValue = 5, MinValue = -50, Step = 2, Value = 5 });
			model.AddArgs("Y", new Parameter { MaxValue = 70, MinValue = -70, Step = 2, Value = 1 });
			model.AddArgs("Z", new Parameter { MaxValue = 10, MinValue = -20, Step = 2, Value = 2 });
			// define consequence calculator
			model.AddConsequenceToCalculate(delegate(DestrictiveModel model1) {
				model1.SetConcequence("IsMaxValueX",
									   model1.GetArgs("X").Value > model1.GetArgs("X").MaxValue);
				model1.SetConcequence("IsMaxValueY",
									   model1.GetArgs("Y").Value > model1.GetArgs("Y").MaxValue);
				model1.SetConcequence("IsMaxValueZ",
									   model1.GetArgs("Z").Value > model1.GetArgs("Z").MaxValue);
				model1.SetConcequence("IsMinValueX",
									   model1.GetArgs("X").Value < model1.GetArgs("X").MinValue);
				model1.SetConcequence("IsMinValueY",
									   model1.GetArgs("Y").Value < model1.GetArgs("Y").MinValue);
				model1.SetConcequence("IsMinValueZ",
									   model1.GetArgs("Z").Value < model1.GetArgs("Z").MinValue);
				model1.SetConcequence("Result",
									   model1.GetArgs("Z").Value *
									   (model1.GetArgs("Y").Value +
										Math.Pow(model1.GetArgs("X").Value, 3)));
			});
			var optimizer = new Optimizer(model, delegate(DestrictiveModel model1) {
				// must conditions
				if ((bool)(model1.GetConcequence("IsMaxValueX"))) {
					return double.MinValue;
				}
				if ((bool)(model1.GetConcequence("IsMaxValueY"))) {
					return double.MinValue;
				}
				if ((bool)(model1.GetConcequence("IsMaxValueZ"))) {
					return double.MinValue;
				}
				if ((bool)(model1.GetConcequence("IsMinValueX"))) {
					return double.MinValue;
				}
				if ((bool)(model1.GetConcequence("IsMinValueY"))) {
					return double.MinValue;
				}
				if ((bool)(model1.GetConcequence("IsMinValueZ"))) {
					return double.MinValue;
				}
				// optimized condition, more positive one are taken
				return (double)model1.GetConcequence("Result") * -1.0;
				// find minimum
			});
			var r = new Random();

			double bestBenchmark = 0;
			KeyValuePair<string, Parameter>[] bestParameters = model.GetArgs();

			// repeat as many times as possible;) --> to find the best optimum
			for (int i = 0; i < 10; i++) {
				// start point
				model.GetArgs("X").Value = r.Next(model.GetArgs("X").MinValue, model.GetArgs("X").MaxValue);
				model.GetArgs("Y").Value = r.Next(model.GetArgs("Y").MinValue, model.GetArgs("Y").MaxValue);
				model.GetArgs("Z").Value = r.Next(model.GetArgs("Z").MinValue, model.GetArgs("Z").MaxValue);

				// find minimum of  Z*(Y + X^3) 
				while (optimizer.Run()) {
				}

				// local optimum found
				Logger.WriteDebug(model.GetArgs("X").Value.ToString());
				Logger.WriteDebug(model.GetArgs("Y").Value.ToString());
				Logger.WriteDebug(model.GetArgs("Z").Value.ToString());
				var localBenchmark = (double)model.GetConcequence("Benchmark");
				Logger.WriteDebug("Point reached:" + localBenchmark);
				if (localBenchmark > bestBenchmark) {
					bestParameters =
						(from s in model.GetArgs() select new KeyValuePair<string, Parameter>(s.Key, (Parameter)s.Value.Clone())).
							ToArray();
					bestBenchmark = localBenchmark;
				}
			}
			// best model found until now
			Logger.WriteDebug("*****************************************************************");
			Logger.WriteDebug("best model found until now");
			Logger.WriteDebug("*****************************************************************");

			Logger.WriteDebug(((from p in bestParameters where p.Key == "X" select p.Value).First().Value).ToString());
			Logger.WriteDebug(((from p in bestParameters where p.Key == "Y" select p.Value).First().Value).ToString());
			Logger.WriteDebug(((from p in bestParameters where p.Key == "Z" select p.Value).First().Value).ToString());
			;

			Logger.WriteDebug("Point reached:" + bestBenchmark);
			Logger.WriteDebug("Calculation needed:" + optimizer.CalculationDone);
		}

		#endregion
	}
}